﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Microsoft.SharePoint.Client;

namespace SPNetworkTopology.ExternalWindows.ViewModel
{
    class SPListInputViewModel : DataLinkingViewModelBase
    {
        string listName = null;
        string siteName = null;
        string validationMessage;
        bool isValid;

        ClientContext context;
       
        Web siteWeb;
        List spList;

        private Visibility isProgressbarVisible = Visibility.Collapsed;

        public BackgroundWorker worker;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="dataLinking">DataLinking</param>
        public SPListInputViewModel(DataLinking dataLinking)
            : base(dataLinking)
        {
            this.ResetErrorMessage(false);

            this.worker = new BackgroundWorker();
            this.worker.WorkerReportsProgress = true;
            this.worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            this.worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);            
        }

        public bool HasNoError
        {
            get
            {
                return isValid;
            }
        }

        /// <summary>
        /// Progressbar Visibility
        /// </summary>
        public Visibility IsProgressbarVisible
        {
            set
            {
                this.isProgressbarVisible = value;
                this.OnPropertyChanged("IsProgressbarVisible");
            }
            get
            {
                return this.isProgressbarVisible;
            }
        }

        /// <summary>
        /// SharePoint list name
        /// </summary>
        public string ListName
        {
            set
            {
                this.listName = value;

                if (this.DataLinking.SPListName != null &&
                    this.DataLinking.SPListName.Equals(value, StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }
               
                //Set the SharePoint list name
                this.DataLinking.SPListName = value;
            }
            get
            {
                return this.listName;
            }
        }

        /// <summary>
        /// SharePoint site name
        /// </summary>
        public string SiteName
        {
            set
            {
                siteName = value;

                if (this.DataLinking.SPSiteName != null &&
                    this.DataLinking.SPSiteName.Equals(value, StringComparison.OrdinalIgnoreCase))
                {
                    return;
                }

                //Set the site name
                this.DataLinking.SPSiteName = value;
            }
            get
            {
                return this.siteName;
            }
        }

        public Visibility SiteErrorMessageVisibility
        {
            set;
            get;
        }

        public Visibility ListErrorMessageVisibility
        {
            set;
            get;
        }

        public Visibility ErrorMessageVisibility
        {
            set;
            get;
        }

        public string ValidationMessage
        {
            set
            {
                validationMessage = value;
            }
            get
            {
                return this.validationMessage;
            }
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            worker.ReportProgress(5);
            ValidateCommandAction();
            e.Result = this;            
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.IsProgressbarVisible = Visibility.Visible;
        }

        private void ValidateCommandAction()
        {
            this.ResetErrorMessage(false);

            if (String.IsNullOrEmpty(this.siteName))
            {
                this.SetErrorMessage("Site name cannot be empty", true);
                return;
            }
            if (String.IsNullOrEmpty(this.listName))
            {
                this.SetErrorMessage("List name cannot be empty", false);
                return;
            }

            if (!this.ValidateSPSiteAction(this.siteName))
            {
                return;
            }

            this.ValidateSPList(this.listName);
        }

        /// <summary>
        /// Validate the SPList existence
        /// </summary>
        /// <param name="spListName">SharePoint List name - String</param>
        private void ValidateSPList(string spListName)
        {
            try
            {
                this.IsProgressbarVisible = Visibility.Visible;

                //Load the SPList 
                IEnumerable<List> listCollection = context.LoadQuery(siteWeb.Lists);
                context.ExecuteQuery();

                //Check the SPList existence
                bool listExists = listCollection.Any(list => list.Title.Equals(spListName, StringComparison.OrdinalIgnoreCase));

                if (!listExists)
                {
                    this.SetErrorMessage(SPNetworkTopologyResource.SPListExistenceValidationErrorMessage, false);
                    return;
                }

                this.spList = listCollection.Where(list => list.Title.Equals(spListName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

                //Load the SPList columns
                var columnList = context.LoadQuery(this.spList.Fields);
                context.ExecuteQuery();
                var spColumns = columnList.Select(listItem => listItem.Title);

                //Validate the SPColumn schema
                IEnumerable<bool> spColumnsCheck = this.DataLinking.ExpectedSPColumns.Select(s => spColumns.Contains(s));
                if (spColumnsCheck.Contains(false))
                {
                    this.SetErrorMessage(String.Format(SPNetworkTopologyResource.SPListSchemaValidationErrorMessage, Environment.NewLine), false);
                    return;
                }

                this.DataLinking.SPListGUID = this.spList.Id.ToString();

                this.ResetErrorMessage(true);
            }
            catch (Exception)
            {
                this.SetErrorMessage(SPNetworkTopologyResource.SPListExistenceValidationErrorMessage, false);
            }
        }

        private bool ValidateSPSiteAction(string siteUrl)
        {
            try
            {
                this.IsProgressbarVisible = Visibility.Visible;
                context = new ClientContext(siteUrl);
                this.siteWeb = context.Web;
                return true;
            }
            catch (Exception)
            {
                this.SetErrorMessage(String.Format(SPNetworkTopologyResource.SPSiteValidationErrrorMessage, Environment.NewLine), true);
                return false;
            }
        }

        private void SetErrorMessage(string errorMessage, bool isSite)
        {
            this.isValid = false;
            this.ValidationMessage = String.Format(errorMessage, Environment.NewLine);
            this.OnPropertyChanged("ValidationMessage");

            this.ErrorMessageVisibility = Visibility.Visible;
            this.OnPropertyChanged("ErrorMessageVisibility");

            if (isSite)
            {
                this.SiteErrorMessageVisibility = Visibility.Visible;
                this.OnPropertyChanged("SiteErrorMessageVisibility");
            }
            else
            {
                this.ListErrorMessageVisibility = Visibility.Visible;
                this.OnPropertyChanged("ListErrorMessageVisibility");
            }
        }

        private void ResetErrorMessage(bool isAfterValidation)
        {
            this.isValid = isAfterValidation;
            this.validationMessage = String.Empty;
            this.OnPropertyChanged("ValidationMessage");

            this.SiteErrorMessageVisibility = Visibility.Collapsed;
            this.OnPropertyChanged("SiteErrorMessageVisibility");

            this.ErrorMessageVisibility = Visibility.Collapsed;
            this.OnPropertyChanged("ErrorMessageVisibility");

            this.ListErrorMessageVisibility = Visibility.Collapsed;
            this.OnPropertyChanged("ListErrorMessageVisibility");

            this.IsProgressbarVisible = Visibility.Collapsed;
        }

        public override string DisplayName
        {
            get
            {
                return SPNetworkTopologyResource.SPListInputViewHeaderBlurb;
            }
        }

        internal override bool IsValid()
        {
            if (this.worker.IsBusy)
            {
                return false;
            }

            return true;
        }
    }
}
